﻿using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using RainEngine.Rendering;

namespace RainEngine.Effects
{
    /// <summary>
    /// 引擎内建的effect，用于绘制水面。
    /// </summary>
    public class WaterEffect : Effect
    {
        EffectParameter worldViewProjParam;
        EffectParameter worldParam;
        EffectParameter worldReflectionViewProjParam;
        EffectParameter eyePositionParam;

        EffectParameter lightDirectionParam;
        EffectParameter bumpTextureParam;
        EffectParameter bumpTextureUVTileParam;
        EffectParameter reflectionMapParam;
        EffectParameter refractionMapParam;
        
        EffectParameter waveHeightParam;
        EffectParameter windDirectionParam;
        EffectParameter windForceParam;
       
        EffectParameter timeParam;

        Matrix world = Matrix.Identity;
        Matrix view = Matrix.Identity;
        Matrix projection = Matrix.Identity; 
        Matrix reflectionView= Matrix.Identity; 

        EffectDirtyFlags dirtyFlags = EffectDirtyFlags.All;

        /// <summary>
        /// 获取或设置世界矩阵。世界矩阵改变时会影响effect的WorldViewProj参数
        /// </summary>
        public Matrix World
        {
            get { return world; }
            set
            {
                world = value;
                dirtyFlags |= EffectDirtyFlags.WorldViewProj;
            }
        }

        /// <summary>
        /// 获取或设置视矩阵,视矩阵改变时会影响effect的WorldViewProj。
        /// </summary>
        public Matrix View
        {
            get { return view; }
            set
            {
                view = value;
                dirtyFlags |= EffectDirtyFlags.WorldViewProj;
            }
        }

        /// <summary>
        /// 获取或设置投影矩阵,,投影矩阵改变时会影响effect的WorldViewProj。
        /// </summary>
        public Matrix Projection
        {
            get { return projection; }
            set
            {
                projection = value;
                dirtyFlags |= EffectDirtyFlags.WorldViewProj;
            }
        }
        
        /// <summary>
        /// 获取或设置反射相机的视矩阵。
        /// </summary>
        public Matrix ReflectionView
        {
            get { return reflectionView; }

            set
            {
                reflectionView = value;
                dirtyFlags |= EffectDirtyFlags.WorldViewProj;
            }
        }

        /// <summary>
        /// 获取或设置相机位置。
        /// </summary>
        public Vector3 EyePosition
        {
            get { return eyePositionParam.GetValueVector3(); }
            set { eyePositionParam.SetValue(value); }
        }

        /// <summary>
        /// 获取或设置光线方向
        /// </summary>
        public Vector3 LightDirection
        {
            get { return lightDirectionParam.GetValueVector3(); }
            set { lightDirectionParam.SetValue(value); }
        }

        /// <summary>
        /// 获取或设置水面的凹凸贴图。
        /// </summary>
        public Texture2D BumpTexture
        {
            get { return bumpTextureParam.GetValueTexture2D(); }
            set { bumpTextureParam.SetValue(value); }
        }

        /// <summary>
        /// 获取或设置反射贴图
        /// </summary>
        public Texture2D ReflectionMap
        {
            get { return reflectionMapParam.GetValueTexture2D(); }
            set { reflectionMapParam.SetValue(value); }
        }

        /// <summary>
        /// 获取或设置折射贴图
        /// </summary>
        public Texture2D RefractionMap
        {
            get { return refractionMapParam.GetValueTexture2D(); }
            set { refractionMapParam.SetValue(value); }
        }
        
        /// <summary>
        /// 获取或设置风的强度，即水流的移动速度，默认值为0.002。
        /// </summary>
        public float WindForce
        {
            get { return windForceParam.GetValueSingle (); }
            set { windForceParam.SetValue(value);}
        }

        /// <summary>
        /// 获取或设置振幅，默认为0.3
        /// </summary>
        public float WaveHeight
        {
            get { return waveHeightParam.GetValueSingle(); }
            set { waveHeightParam.SetValue(value);}
        }

        /// <summary>
        /// 获取或设置波长，默认为0.1，其实改变的凹凸纹理的平铺次数，若波长为0.1，则平铺次数为倒数10次
        /// </summary>
        public float WaveLength
        {
            get { return 1.0f/bumpTextureUVTileParam.GetValueVector2().X ; }
            set { bumpTextureUVTileParam.SetValue(new Vector2(1.0f / value,1.0f/value));}
        }

        /// <summary>
        /// 水流方向，默认为向前
        /// </summary>
        public Vector3 WindDirection
        {
            get { return windDirectionParam.GetValueVector3 (); }
            set { windDirectionParam.SetValue(value); }
        }

        public float Time
        {
            set{ timeParam.SetValue(value);}
        }
        

        /// <summary>
        /// 创建一个新WaterEffect对象。
        /// </summary>
        public WaterEffect(GraphicsDevice device)
            : base(device, Resource.WaterEffectBin)
        {
            CacheEffectParameters(null);
        }

        /// <summary>
        /// 通过从一个已经存在的对象中复制参数创建一个新WaterEffect对象。
        /// </summary>
        protected WaterEffect(WaterEffect cloneSource)
            : base(cloneSource)
        {
            CacheEffectParameters(cloneSource);

            world = cloneSource.world;
            view = cloneSource.view;
            projection = cloneSource.projection;
            reflectionView = cloneSource.reflectionView;
        }


        /// <summary>
        /// 创建一个当前WaterEffect对象的副本。
        /// </summary>
        public override Effect Clone()
        {
            return new WaterEffect(this);
        }

        /// <summary>
        /// 缓存effect的参数。
        /// </summary>
        void CacheEffectParameters(WaterEffect cloneSource)
        {
            worldParam = Parameters["World"];
            worldViewProjParam = Parameters["WorldViewProj"];
            worldReflectionViewProjParam = Parameters["WorldReflectionViewProj"];
            eyePositionParam = Parameters["EyePosition"];

            lightDirectionParam = Parameters["LightDirection"];
            bumpTextureParam = Parameters["BumpTexture"];
            bumpTextureUVTileParam = Parameters["BumpTextureUVTile"];
            reflectionMapParam = Parameters["ReflectionMap"];
            refractionMapParam = Parameters["RefractionMap"];
            
            waveHeightParam = Parameters["WaveHeight"];            
            windDirectionParam = Parameters["WindDirection"];
            windForceParam = Parameters["WindForce"];                        
            
            timeParam=Parameters ["Time"]; 
        }

        /// <summary>
        /// 在施加effect前根据需要重新计算effect参数。
        /// </summary>
        protected override void OnApply()
        {
            // 首先判断是否需要重新计算world+view+projection矩阵。
            if ((dirtyFlags & EffectDirtyFlags.WorldViewProj) != 0)
            {
                Matrix worldView = Matrix.Multiply(world, view);
                Matrix worldViewProj = Matrix.Multiply(worldView, projection);
                Matrix worldReflectionView = Matrix.Multiply(world, reflectionView);  
                Matrix worldReflectionViewProj = Matrix.Multiply(worldReflectionView, projection);
                
                worldViewProjParam.SetValue(worldViewProj);
                worldReflectionViewProjParam.SetValue(worldReflectionViewProj);

                dirtyFlags &= ~EffectDirtyFlags.WorldViewProj;
            }            
        }
    }
}